package io.gitee.zhangbinhub.acp.cloud.integration

import io.gitee.zhangbinhub.acp.cloud.AcpCloudComponentAutoConfiguration
import io.gitee.zhangbinhub.acp.cloud.AcpCloudLoadBalancerAutoConfiguration
import io.gitee.zhangbinhub.acp.cloud.AcpCloudLogConfiguration
import io.gitee.zhangbinhub.acp.cloud.AcpCloudNamiAutoConfiguration
import io.gitee.zhangbinhub.acp.cloud.conf.AcpCloudLogServerConfiguration
import io.gitee.zhangbinhub.acp.cloud.log.consumer.AcpCloudLogConsumer
import io.gitee.zhangbinhub.acp.cloud.log.consumer.DefaultLogProcess
import io.gitee.zhangbinhub.acp.cloud.log.consumer.LogProcess
import io.gitee.zhangbinhub.acp.core.common.log.LogFactory
import org.noear.solon.Solon
import org.noear.solon.Utils
import org.noear.solon.admin.client.annotation.EnableAdminClient
import org.noear.solon.admin.client.config.ClientProperties
import org.noear.solon.cloud.CloudClient
import org.noear.solon.cloud.CloudManager
import org.noear.solon.cloud.annotation.CloudEvent
import org.noear.solon.cloud.annotation.EventLevel
import org.noear.solon.core.AppContext
import org.noear.solon.core.LoadBalance
import org.noear.solon.core.Plugin
import org.noear.solon.core.event.AppLoadEndEvent
import org.noear.solon.core.event.AppPluginLoadEndEvent
import org.noear.solon.core.event.EventBus
import org.noear.solon.health.detector.DetectorManager
import java.net.URI

class XPluginImp : Plugin {
    private val logFactory = LogFactory.getInstance(this.javaClass)
    override fun start(context: AppContext) {
        context.beanMake(AcpCloudComponentAutoConfiguration::class.java)
        context.beanMake(AcpCloudLoadBalancerAutoConfiguration::class.java)
        context.beanMake(AcpCloudLogConfiguration::class.java)
        context.beanMake(AcpCloudNamiAutoConfiguration::class.java)
        context.app().onEvent(AppPluginLoadEndEvent::class.java) {
            initSolonAdminClient(context)
            initLogServerConsumer(context)
        }
    }

    private fun initSolonAdminClient(context: AppContext) {
        if (Solon.app().source().isAnnotationPresent(EnableAdminClient::class.java)) {
            if (Solon.cfg().getBool("solon.admin.client.enabled", true)) {
                context.beanScan("org.noear.solon.admin.client")
                context.lifecycle(Int.MAX_VALUE) {
                    context.getBean(ClientProperties::class.java)?.also { clientProperties ->
                        clientProperties.serverUrl.let { url ->
                            URI.create(url)
                        }.let { serverUri ->
                            if (serverUri.scheme == "lb") {
                                LoadBalance.get(Solon.cfg().appGroup(), serverUri.host).server
                                    ?: "http://${serverUri.host}:${serverUri.port}"
                            } else {
                                serverUri.toString()
                            }
                        }.apply {
                            clientProperties.serverUrl = this
                        }
                    }
                }
                EventBus.subscribe(AppLoadEndEvent::class.java) {
                    DetectorManager.start(*arrayOf("*"))
                }
            }
        }
    }

    private fun initLogServerConsumer(context: AppContext) {
        context.getBean(AcpCloudLogServerConfiguration::class.java).let { acpCloudLogServerConfiguration ->
            if (acpCloudLogServerConfiguration.enabled) {
                logFactory.info("Log Server is enabled!")
                val anno = CloudEvent(
                    value = acpCloudLogServerConfiguration.destination,
                    topic = acpCloudLogServerConfiguration.destination,
                    group = "",
                    tag = "",
                    level = EventLevel.cluster,
                    channel = "",
                    qos = 1
                )
                val handle = AcpCloudLogConsumer(context.getBean(LogProcess::class.java) ?: DefaultLogProcess())
                CloudManager.register(anno, handle)
                if (CloudClient.event() != null) {
                    val topic = Solon.cfg().getByTmpl(Utils.annoAlias(anno.value, anno.topic))
                    val group = Solon.cfg().getByTmpl(anno.group)
                    CloudClient.event().attention(
                        anno.level,
                        anno.channel,
                        group,
                        topic,
                        anno.tag,
                        anno.qos,
                        handle
                    )
                }
                logFactory.info("Register CloudEventHandler<AcpCloudLogConsumer> topic[${acpCloudLogServerConfiguration.destination}]")
            }
        }
    }
}